﻿#include "ldUtils.h"
#include <QProcess>
#include <QStorageInfo>


int CreateSockPipe(int nPortNo, int nPipe[2])
{
    int iSts = 0;
    printf("PIPE 创建");
// Windows中创建管道（linux中的管道）
#ifdef WIN32
    int iSockfd;
    int iSocklen;
    long lTemp;
    struct sockaddr_in srcAddr;
    struct sockaddr_in dstAddr;
    WSADATA data;
    int iErno;

    // 变量初始化
    iSockfd = -1;
    iSocklen = sizeof(struct sockaddr_in);
    lTemp = 0;
    iErno = 0;
    memset(&srcAddr, 0, sizeof(srcAddr));
    memset(&dstAddr, 0, sizeof(dstAddr));
    memset(&data, 0, sizeof(data));

    // WinSock初始化
    iErno = WSAStartup(MAKEWORD(2,0),&data);
    if(iErno != 0) {
        printf("winsock init failure");
        return -1;
    }

    // 创建socket
    iSockfd = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
    if(iSockfd == -1) {
        printf("create socket error");
        return -1;
    }

    // 设置sockaddr_in 结构体
    memset(&srcAddr, 0, sizeof(srcAddr));
    srcAddr.sin_port = htons((u_short)nPortNo);
    srcAddr.sin_family = AF_INET;
    srcAddr.sin_addr.s_addr =htonl(INADDR_ANY);

    // 绑定
    iSts = bind(iSockfd, (struct sockaddr*)&srcAddr,sizeof(srcAddr));
    if(iSts != 0) {
        printf("bind failure");
        return -1;
    }

    // 监听
    iSts = listen(iSockfd, 1);
    if(iSts != 0) {
        printf("listen failure");
        return -1;
    }
    // 地址取得
    iSts = getsockname(iSockfd, (struct sockaddr *)&dstAddr, &iSocklen);
    if( iSts != 0) {
        printf("getsockname failure");
        return -1;
    }
    // WinSock初始化
    nPipe[1] = socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
    if(nPipe[1] == -1) {
        printf("nPipe[1] socket create failure");
        return -1;
    }

    // socket阻塞
    lTemp  =1;
    ioctlsocket(nPipe[1], FIONBIO, (u_long*)&lTemp);
    dstAddr.sin_addr.s_addr =htonl(INADDR_LOOPBACK);

    // 连接
    iSts = connect(nPipe[1], (struct sockaddr*)&dstAddr, sizeof(dstAddr));
    if(iSts == -1) {
        lTemp = WSAGetLastError();
        if ((lTemp != WSAEWOULDBLOCK)&& (lTemp != WSAEINPROGRESS)) {
            printf("connect failure");
            return -1;
        }
    }

    // 接受连接，生成新的socket ID
    nPipe[0] = (int)accept(iSockfd, (struct sockaddr *)&srcAddr, &iSocklen);
    if(nPipe[0] == -1) {
        printf("accept failure");
        return -1;
    }

    // 去掉socket的阻塞
    lTemp  =0;
    ioctlsocket(nPipe[1], FIONBIO,(u_long*)&lTemp);
    closesocket(iSockfd);
#else
    // linux中直接创建管道
    iSts = socketpair(AF_UNIX, SOCK_STREAM, 0,nPipe);
    if(iSts != 0) {
        printf("socketpair failure");
        return -1;
    }
#endif
    return 0;
}

#ifdef WIN32
//求磁盘剩余空间
quint64 getDiskFreeSpace(QString driver)
{
    QString strDiver;
    LPCWSTR lpcwstrDriver=(LPCWSTR)driver.utf16();

        ULARGE_INTEGER liFreeBytesAvailable, liTotalBytes, liTotalFreeBytes;

        if( !GetDiskFreeSpaceEx( lpcwstrDriver, &liFreeBytesAvailable, &liTotalBytes, &liTotalFreeBytes) )
        {
            qDebug() << "ERROR: Call to GetDiskFreeSpaceEx() failed.";
            return 0;
        }

        //磁盘总空间
        qDebug() << "liTotalBytes=" << liTotalBytes.QuadPart/1024/1024/1024 << "G";
        //磁盘剩余空间
        qDebug() << "liTotalFreeBytes=" << liTotalFreeBytes.QuadPart/1024/1024/1024 << "G";

        return (quint64) liTotalFreeBytes.QuadPart/1024/1024/1024;
}
#else
quint64 getDiskFreeSpace(QString driver)
{
    quint64 nDiskSize = 0;
    QStorageInfo storage = QStorageInfo::root();
    storage.refresh();  //获得最新磁盘信息
    storage.device();

    QDir curDir(driver);
    storage.setPath(curDir.root().path());
    nDiskSize = storage.bytesAvailable()/1000/1000;
    return nDiskSize;
}
#endif

int SockPipeWrite(int nPipe0,uint8_t* pData,int nLen)
{
    if(nPipe0 <= 0)
    {
        return -1;

    }
    return send(nPipe0,(const char*)pData,nLen,0);
}


int SockPipeRead(SOCKET nPipe1,uint8_t* pData,int nLen)
{
    int    nReadLen = 0;
    fd_set fdSocket;
    int     s_maxFd = 0;
    struct timeval TimeoutVal;
    if(nPipe1 <=0 )
        return -1;
    FD_ZERO(&fdSocket);
    FD_SET(nPipe1, &fdSocket);//将sListen添加进该集合
    s_maxFd   = s_maxFd > nPipe1 ? s_maxFd:nPipe1;
    s_maxFd = s_maxFd+1;

    TimeoutVal.tv_sec  = 2;
    TimeoutVal.tv_usec = 0;

    int nRet = select(s_maxFd, &fdSocket, NULL, NULL, &TimeoutVal);//
    if (nRet <= 0){
        printf("%s select failed!\n",__FUNCTION__);
        return -1;
    }
    if (FD_ISSET(nPipe1, &fdSocket ))
    {
      nReadLen = recv(nPipe1,(char *)pData,nLen, 0);
    }
    return nReadLen;
}


int CloseSockPipe(int nPipe[2])
{
#ifdef WIN32
    closesocket(nPipe[0]);
    closesocket(nPipe[1]);
#else
    close(nPipe[0]);
    close(nPipe[1]);
#endif
    return 0;
}







void GetGateWay(QString& gateway)
{
#ifdef WIN32
      QProcess cmd_pro ;
      QString cmd_str = QString("route print");
      cmd_pro.start("cmd.exe", QStringList() << "/c" << cmd_str);
      cmd_pro.waitForStarted();
      cmd_pro.waitForFinished();
      QString result = cmd_pro.readAll();
      QString pattern("0\\.0\\.0\\.0 *(0|128)\\.0\\.0\\.0 *([0-9\\.]*)");
      QRegExp rx(pattern);
      int pos = result.indexOf(rx);
      if (pos >= 0)
      {
          qDebug()<<"reg::"<<rx.cap(2);
          gateway = rx.cap(2);
      }
#else
    // 创建进程对象
    QProcess process;

    // 设置要执行的命令及参数
    QStringList arguments = {"-c", "ip route show default"};
    process.setProgram("bash");
    process.setArguments(arguments);

    // 开始执行命令
    process.start();

    // 等待命令执行完成
     if (process.waitForFinished(-1) == false) {
         printf("Command execution failed or timed out.");
         return ;
     }

     // 读取命令输出结果
    QByteArray outputData = process.readAllStandardOutput();
    QString outputText = QString::fromUtf8(outputData).trimmed();
    int start = outputText.indexOf("via ");
    int stop  = outputText.indexOf("dev ");


    // 打印输出结果
    gateway = outputText.section(" ",2,2);
#endif
}


void SetLocTime(int nYear,int nMonth,int nDay,int nHour,int nMinute,int nSecond)
{
    char cBuff[256] = {0};

    if(nMonth == 0  && nDay == 0)
        return;

    if(nMonth < 1 || nMonth > 12)
    {
        nMonth = 1;
    }

    if(nDay < 1 || nDay > 32)
    {
        nDay = 1;
    }

    static  int isSetTime = 0;

    if(isSetTime == 0)
    {//不需要每帧都改时间，启动改一次
       sprintf(cBuff,"date -s \"%04d-%02d-%02d %02d:%02d:%02d\"",nYear,nMonth,nDay,nHour,nMinute,nSecond);
       #ifdef WIN32
          SYSTEMTIME time;
          //QDateTime tmp = QDateTime::currentDateTime();
          time.wYear = nYear;
          time.wMonth = nMonth;
          time.wDay = nDay;
          time.wHour = nHour;
          time.wMinute = nMinute;
          time.wSecond = nSecond;
          SetLocalTime(&time);
       #else
          QProcess::startDetached(QString(cBuff)); // 0312 表示3月12日，1025表示当前时分
//       QProcess::startDetached("sudo hwclock -w"); // 同步系统时间
//       QProcess::startDetached("sudo hwclock -s"); // 保存配置
       #endif
          isSetTime = true;
     }
}


//OpenCV里貌似没有判断rect1是否在rect2里面的功能，所以自己写一个吧
bool isInside(cv::Rect rect1, cv::Rect rect2)
{
    return (rect1 == (rect1&rect2));
}

//OpenCV貌似也没有获取矩形中心点的功能，还是自己写一个
cv::Point getCenterPoint(cv::Rect rect)
{
    cv::Point cpt;
    cpt.x = rect.x + cvRound(rect.width/2.0);
    cpt.y = rect.y + cvRound(rect.height/2.0);
    return cpt;
}


/**
 ******************************************************************************
 * @brief   tv0 与 tv1 相减, 返回double类型时间差
******************************************************************************
 */
int  timediff_ms(struct timeval * tv0, struct timeval * tv1)
{
    double time1, time2;

    time1 = tv0->tv_sec + (tv0->tv_usec / 1000000.0);
    time2 = tv1->tv_sec + (tv1->tv_usec / 1000000.0);

    time1 = time1 - time2;
    if (time1 < 0)
        time1 = -time1;
    return time1*1000.0;
}


int64_t gettime_ms()
{
    int64_t   time64Ms;
   struct timeval  timeNow;
   int nRes = gettimeofday(&timeNow,NULL);
   time64Ms = 1000*(int64_t)timeNow.tv_sec + timeNow.tv_usec/1000.0;
   return  time64Ms;
}
